# frozen_string_literal: true

module API
  class VulnerabilityFindings < ::API::Base
    include PaginationParams
    include ::Gitlab::Utils::StrongMemoize

    feature_category :vulnerability_management
    urgency :low

    helpers do
      def pipeline
        strong_memoize(:pipeline) do
          if params[:pipeline_id]
            user_project.all_pipelines.id_in(params[:pipeline_id]).first
          else
            user_project.latest_ingested_security_pipeline
          end
        end
      end

      def vulnerability_findings
        @vulnerability_findings ||= begin
          return paginate(Kaminari.paginate_array([])) unless pipeline

          with_pure_finder || with_adaptive_finder
        end
      end

      def with_pure_finder
        pure_finder = Security::PureFindingsFinder.new(pipeline, params: declared_params)
        return unless pure_finder.available?

        pure_finder.execute
                   .tap { |findings| findings.each(&:remediations) } # initiates Batchloader
                   .then { |findings| paginate(findings) }
      end

      def with_adaptive_finder
        result = Security::FindingsFinder.new(pipeline, params: declared_params).execute
        paginate(result)

        result.findings
      end
    end

    before do
      authenticate!
    end

    params do
      requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
    end
    resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
      params do
        optional :report_type,
          type: Array[String],
          coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce,
          desc: 'The type of report vulnerability belongs to',
          values: ::Vulnerabilities::Finding.report_types.keys,
          default: ::Vulnerabilities::Finding.report_types.keys

        optional :scope,
          type: String,
          desc: 'Return vulnerabilities for the given scope: `dismissed` or `all`',
          default: 'dismissed',
          values: %w[all dismissed]

        optional :severity,
          type: Array[String],
          coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce,
          desc: 'Returns vulnerabilities belonging to specified severity level: '\
                '`info`, `unknown`, `low`, `medium`, `high`, or `critical`. Defaults to all',
          values: ::Vulnerabilities::Finding.severities.keys,
          default: ::Vulnerabilities::Finding.severities.keys

        optional :confidence,
          type: Array[String],
          coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce,
          desc: 'Returns vulnerabilities belonging to specified confidence level: '\
                '`ignore`, `unknown`, `experimental`, `low`, `medium`, `high`, or `confirmed`. '\
                'Defaults to all',
          values: ::Vulnerabilities::Finding.confidences.keys,
          default: ::Vulnerabilities::Finding.confidences.keys

        optional :pipeline_id, type: String, desc: 'The ID of the pipeline'

        use :pagination
      end
      desc 'Get a list of project vulnerability findings' do
        is_array true
        success ::Vulnerabilities::FindingEntity
      end
      get ':id/vulnerability_findings' do
        authorize! :read_security_resource, user_project

        present vulnerability_findings,
          with: ::Vulnerabilities::FindingEntity,
          request: GrapeRequestProxy.new(request, current_user)
      end
    end
  end
end
